/*
 * StabSolver.cpp
 *
 *  Created on: Sep 18, 2011
 *      Author: correa
 */

#include <Graph.h>
#include "StabSolver.h"
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <sstream>
#include <cplex.h>

// #define NDEBUG
#include <assert.h>

// StabModel

char **	StabModel::rowname() {
	if (!rowname_v)
		rowname_v = new char*[n+m];
	return rowname_v;
}

void StabModel::delrowname() {
	if (rowname_v) {
		delete rowname_v;
		rowname_v = NULL;
	}
}

const char * StabModel::rnamestore(int * spc) {
	if (!rnamestore_v) {
		storespace_v = (m+n)*30;
		rnamestore_v = new char[storespace_v];
	}
	*spc = storespace_v;
	return rnamestore_v;
}

void StabModel::delrnamestore() {
	if (rnamestore_v) {
		delete rnamestore_v;
		rnamestore_v = NULL;
	}
}

char **	StabModel::colname() {
	if (!colname_v)
		colname_v = new char*[n+1];
	return colname_v;
}

void StabModel::delcolname() {
	if (colname_v) {
		delete colname_v;
		colname_v = NULL;
	}
}

const char * StabModel::cnamestore(int * spc) {
	if (!cnamestore_v) {
		storespace_v = (n+1)*30;
		cnamestore_v = new char[storespace_v];
	}
	*spc = storespace_v;
	return cnamestore_v;
}

void StabModel::delcnamestore() {
	if (cnamestore_v) {
		delete cnamestore_v;
		cnamestore_v = NULL;
	}
}

const int * StabModel::rmatbeg() {
	if (!rmatbeg_v)
		rmatbeg_v = new int[m+n];
	return rmatbeg_v;
}

void StabModel::delrmatbeg() {
	if (rmatbeg_v) {
		delete rmatbeg_v;
		rmatbeg_v = NULL;
	}
}

const char * StabModel::sense() {
	if (!sense_v) {
		sense_v = new char[m+n];
		// sense vector
		memset(sense_v, 'L', m+n);
	}
	return sense_v;
}

void StabModel::delsense() {
	if (sense_v) {
		delete sense_v;
		sense_v = NULL;
	}
}

const double * StabModel::rhs() {
	if (!rhs_v)
		rhs_v = new double[n+m];
	return rhs_v;
}

void StabModel::delrhs() {
	if (rhs_v) {
		delete rhs_v;
		rhs_v = NULL;
	}
}

const char * StabModel::type() {
	if (!type_v) {
		type_v = new char[n+1];
		// initialize the vectors according to graph's size
		memset(type_v, 'B', n+1);
	}
	return type_v;
}

void StabModel::deltype() {
	if (type_v) {
		delete type_v;
		type_v = NULL;
	}
}

const char * StabModel::sostype() {
	if (!sostype_v) {
		sostype_v = new char[m];
		// sos vector
		memset(sostype_v, CPX_TYPE_SOS1, m);
	}
	return sostype_v;
}

void StabModel::delsostype() {
	if (sostype_v) {
		delete sostype_v;
		sostype_v = NULL;
	}
}

const int * StabModel::rmatind() {
	if (!rmatind_v) {
		int rmsz = n*m+n;
		rmatind_v = new int[rmsz];
	}
	return rmatind_v;
}

void StabModel::delrmatind() {
	if (rmatind_v) {
		delete rmatind_v;
		rmatind_v = NULL;
	}
}

const double * StabModel::rmatval() {
	if (!rmatval_v) {
		int rmsz = n*m+n;
		rmatval_v = new double[rmsz];
	}
	return rmatval_v;
}

void StabModel::delrmatval() {
	if (rmatval_v) {
		delete rmatval_v;
		rmatval_v = NULL;
	}
}

const int * StabModel::cliquerank() {
	if (!cliquerank_v)
		cliquerank_v = new int[n];
	return cliquerank_v;
}

void StabModel::delcliquerank() {
	if (cliquerank_v) {
		delete cliquerank_v;
		cliquerank_v = NULL;
	}
}

void StabModel::delall() {
	if (n > 0) {
		delrowname();
		delcolname();
		delrnamestore();
		delcnamestore();
		delrmatbeg();
		delsense();
		delrhs();
		deltype();
		delsostype();
		delrmatind();
		delrmatval();
		delcliquerank();
	}
}

StabModel::~StabModel() {
	delall();
}

// StabModeler

StabModeler::StabModeler(Graph * g) : StabModel(g) {
	sprintf(this->prefix, "%s", "x");
	cliquerank();
	ub = Graphs::dsaturCoverSort(g, n, cliquerank_v);
	printf("Clique cover size: %d\n", ub);
}

StabModeler::StabModeler(Graph * g, int col, const char * prefix) : StabModel(g) {
	firstcol_v = col;
	sprintf(this->prefix, "%s", prefix);
	cliquerank();
	ub = Graphs::dsaturCoverSort(g, n, cliquerank_v);
	printf("Clique cover size: %d\n", ub);
}

StabModeler::StabModeler(Graph * g, int * cr) : StabModel(g) {
	sprintf(this->prefix, "%s", "x");
	cliquerank_v = cr;
	int i, max = 0;
	for (i = 0; i < n; i++)
		if (cr[i] > max)
			max = cr[i];
	bool cov[max];
	memset(cov, 0, max*sizeof(bool));
	ub = 0;
	for (i = 0; i < n; i++)
		if (!cov[cr[i]]) {
			cov[cr[i]] = true;
			ub++;
		}
	printf("Clique cover size: %d\n", ub);
}

StabModeler::StabModeler(Graph * g, int col, const char * prefix, int * cr) : StabModel(g) {
	firstcol_v = col;
	sprintf(this->prefix, "%s", prefix);
	cliquerank_v = cr;
	int i, max = 0;
	for (i = 0; i < n; i++)
		if (cr[i] > max)
			max = cr[i];
	bool cov[max];
	memset(cov, 0, max*sizeof(bool));
	ub = 0;
	for (i = 0; i < n; i++)
		if (!cov[cr[i]]) {
			cov[cr[i]] = true;
			ub++;
		}
	printf("Clique cover size: %d\n", ub);
}

StabModeler::~StabModeler() {
}

int StabModeler::stabcols() {
	int iv;
	char namebuf[30];
	int ibuf = 0, lbuf;

	int storespc;
	cnamestore(&storespc);
	colname();
	type();
	rmatind();
	rmatval();
	rhs();
	for (iv = 0; iv < n; iv++) {
		sprintf(namebuf, "%s_%d", prefix, g->vertex(iv)+1);
		lbuf = strlen(namebuf)+1;
		colname_v[iv] = &cnamestore_v[ibuf];
		ibuf += lbuf;
		memcpy(colname_v[iv], namebuf, lbuf);
		rmatind_v[iv] = firstcol_v + iv;
		rmatval_v[iv] = 0.0;
		rhs_v[iv] = 1.0;
	}
	ccnt_v = n;

	return 0;
}

int StabModeler::isolatedrows() {
	int v;
	int ret = 0;

	// edge counting
	rcnt_v = 0;

	// store name counting
	char namebuf[30];
	int ibuf = 0, lbuf;

	// nonzero coefficient counting
	nzcnt_v = 0;

	int iv, j;
	int storespc;
	rnamestore(&storespc);
	rowname();
	rmatbeg();
	rhs();
	rmatind();
	rmatval();
	for (iv = 0; iv < n; iv++) {
		for (j = 0; j < n && (j == iv || !g->hasEdge(iv, j)); j++);
		if (j == n) {
			sprintf(namebuf, "VISO(%s,%d)", prefix, g->vertex(iv)+1);
			lbuf = strlen(namebuf)+1;
			rowname_v[rcnt_v] = &rnamestore_v[ibuf];
			memcpy(rowname_v[rcnt_v], namebuf, lbuf);
			ibuf += lbuf;
			rmatbeg_v[rcnt_v] = nzcnt_v;
			rhs_v[rcnt_v] = 0.0;
			rcnt_v++;
			rmatind_v[nzcnt_v] = iv + firstcol_v;
			rmatval_v[nzcnt_v] = 1.0;
			nzcnt_v++;
		}
	}

	return ret;
}

int StabModeler::edgerows() {
	int ret = 0;

	// edge counting
	rcnt_v = 0;

	// store name counting
	char namebuf[30];
	int ibuf = 0, lbuf;

	// nonzero coefficient counting
	nzcnt_v = 0;

	int iv, j;
	int storespc;
	rnamestore(&storespc);
	rowname();
	rmatbeg();
	rhs();
	rmatind();
	rmatval();
	for (iv = 1; iv < n; iv++) {
		for (j = 0; j < iv; j++) {
			if (g->hasEdge(iv, j)) {
				sprintf(namebuf, "EDGE(%s,%d,%d)", prefix, g->vertex(iv)+1, g->vertex(j)+1);
				lbuf = strlen(namebuf)+1;
				rowname_v[rcnt_v] = &rnamestore_v[ibuf];
				memcpy(rowname_v[rcnt_v], namebuf, lbuf);
				ibuf += lbuf;
				rmatbeg_v[rcnt_v] = nzcnt_v;
				rhs_v[rcnt_v] = 0.0;
				rcnt_v++;
				rmatind_v[nzcnt_v] = iv + firstcol_v;
				rmatval_v[nzcnt_v] = 1.0;
				nzcnt_v++;
				rmatind_v[nzcnt_v] = j + firstcol_v;
				rmatval_v[nzcnt_v] = 1.0;
				nzcnt_v++;
			}
		}
	}

	return ret;
}

int StabModeler::edgesymcuts() {
	int v;
	int ret = 0;

	// edge counting
	rcnt_v = 0;

	// store name counting
	char namebuf[30];
	int ibuf = 0, lbuf;

	// nonzero coefficient counting
	nzcnt_v = 0;

	int iv, j;
	int storespc;
	rnamestore(&storespc);
	rowname();
	rmatbeg();
	rhs();
	rmatind();
	rmatval();

	int max = 0;
	for (j = 0; j < n; j++)
		if (cliquerank_v[j] > max)
			max = cliquerank_v[j];

	bool hascov[max];
	int cov[n];
	int iu;
	for (iv = 0; iv < n; iv++) {
		memset(hascov, 0, max*sizeof(bool));
		cov[iv] = 0;
		for (iu = 0; iu < iv; iu++)
			if (iu != iv && !g->hasEdge(iu, iv) && !hascov[cliquerank_v[iu]]) {
				hascov[cliquerank_v[iu]] = true;
				cov[iv]++;
			}
	}

	int ineqsz = 100/(n*n/(m << 1));
	for (iv = 1; iv < n; iv++) {
		for (j = 0; j < iv; j++) {
			if (g->hasEdge(iv, j) && cov[iv] - cov[j] <= ineqsz && cov[j] - cov[iv] <= ineqsz) {
				sprintf(namebuf, "ESYM1(%s,%d,%d)", prefix, g->vertex(iv)+1, g->vertex(j)+1);
				lbuf = strlen(namebuf)+1;
				rowname_v[rcnt_v] = &rnamestore_v[ibuf];
				memcpy(rowname_v[rcnt_v], namebuf, lbuf);
				ibuf += lbuf;
				rmatbeg_v[rcnt_v] = nzcnt_v;
				rhs_v[rcnt_v] = 0.0;
				rcnt_v++;
				for (iu = 0; iu < n; iu++)
					if (iu != j && g->hasEdge(iv, iu) && !g->hasEdge(j, iu)) {
						if (nzcnt_v - rmatbeg_v[rcnt_v-1] == 8) {
							nzcnt_v = rmatbeg_v[--rcnt_v];
							iu = n + 1;
						}
						else {
							rmatind_v[nzcnt_v] = iu + firstcol_v;
							rmatval_v[nzcnt_v] = -1.0;
							nzcnt_v++;
						}
					}
				if (iu == n) {
					rmatind_v[nzcnt_v] = j + firstcol_v;
					rmatval_v[nzcnt_v] = 1.0;
					nzcnt_v++;
				}
			}
		}
	}
	int it;
	for (iv = 1; iv < n; iv++) {
		for (j = 0; j < iv; j++) {
			if (g->hasEdge(iv, j) && cov[iv] - cov[j] <= ineqsz && cov[j] - cov[iv] <= ineqsz) {
				for (iu = 0; iu < iv; iu++)
					if (iu != j && g->hasEdge(iv, iu) && !g->hasEdge(j, iu))
						for (it = 0; it < iv; it++)
							if ((g->hasEdge(iu, it) && g->hasEdge(it, j)) || ((iu > it && g->hasEdge(iu, it)) || (j > it && g->hasEdge(it, j)))) {
								sprintf(namebuf, "ESYM2(%s,%d,%d,%d,%d)", prefix, g->vertex(iv)+1, g->vertex(j)+1, g->vertex(iu)+1, g->vertex(it)+1);
								lbuf = strlen(namebuf)+1;
								rowname_v[rcnt_v] = &rnamestore_v[ibuf];
								memcpy(rowname_v[rcnt_v], namebuf, lbuf);
								ibuf += lbuf;
								rmatbeg_v[rcnt_v] = nzcnt_v;
								rhs_v[rcnt_v] = 0.0;
								rcnt_v++;
								int is;
								for (is = 0; is < iv; is++)
									if (is != j && is != iu && !g->hasEdge(is, iv) && !g->hasEdge(is, it) && (g->hasEdge(is, j) || g->hasEdge(is, iu))) {
										if (nzcnt_v - rmatbeg_v[rcnt_v-1] == 8) {
											nzcnt_v = rmatbeg_v[--rcnt_v];
											is = iv + 1;
										}
										else {
											rmatind_v[nzcnt_v] = is + firstcol_v;
											rmatval_v[nzcnt_v] = -1.0;
											nzcnt_v++;
										}
									}
								if (is == iv) {
									rmatind_v[nzcnt_v] = j + firstcol_v;
									rmatval_v[nzcnt_v] = 1.0;
									nzcnt_v++;
									rmatind_v[nzcnt_v] = iu + firstcol_v;
									rmatval_v[nzcnt_v] = 1.0;
									nzcnt_v++;
								}
							}
			}
		}
	}

	return ret;
}

static int crankcmp(const void * a, const void * b) {
	return *((int *)a) - *((int *)b);
};

int StabModeler::cliquerows(int * nc) {
	int v;
	int S[n][2];
	for (v = 0; v < n; v++) {
		S[v][0] = cliquerank_v[v];
		S[v][1] = v;
	}

	qsort(S, n, sizeof(int) << 1, crankcmp);

	int ret = 0;

	// edge counting
	rcnt_v = 0;
	*nc = 0;

	// store name counting
	char namebuf[30];
	int ibuf = 0, lbuf;

	// nonzero coefficient counting
	nzcnt_v = 0;

	// clique rows
	int iv;
	int storespc;
	rnamestore(&storespc);
	rowname();
	rmatbeg();
	rhs();
	rmatind();
	rmatval();
	for (iv = 0; iv < n; ) {
		int c = S[iv][0];
		if (c > 0) {
			sprintf(namebuf, "CLIQUE(%s,%d)", prefix, c);
			lbuf = strlen(namebuf)+1;
			rowname_v[rcnt_v] = &rnamestore_v[ibuf];
			memcpy(rowname_v[rcnt_v], namebuf, lbuf);
			ibuf += lbuf;
			rmatbeg_v[rcnt_v] = nzcnt_v;
			rhs_v[rcnt_v] = 0.0;
			rcnt_v++;
			(*nc)++;
			int ikk = nzcnt_v;
			while (iv < n && S[iv][0] == c) {
				rmatind_v[nzcnt_v] = S[iv][1] + firstcol_v;
				rmatval_v[nzcnt_v] = 1.0;
				nzcnt_v++;
				iv++;
			}
			if (nzcnt_v - ikk <= 2) {
				rcnt_v--;
				ibuf -= lbuf;
				nzcnt_v = ikk;
			}
		}
		else
			iv++;
	}

	return ret;
}

int StabModeler::scalerows(int begin, int end, int col, double coeff) {
	rmatbeg();
	rmatind();
	rmatval();
	for (rcnt_v = 0; begin <= end; rcnt_v++, begin++) {
		rmatbeg_v[rcnt_v] = begin;
		rmatind_v[rcnt_v] = firstcol_v + col;
		rmatval_v[rcnt_v] = coeff;
	}
	nzcnt_v = rcnt_v;
	ccnt_v = 1;

	return 0;
}

int StabModeler::scalerows(int begin, int end, double s) {
	rmatbeg();
	rhs();
	for (rcnt_v = 0; begin <= end; rcnt_v++, begin++) {
		rmatbeg_v[rcnt_v] = begin;
		rhs_v[rcnt_v] = s;
	}
	nzcnt_v = 0;
	ccnt_v = 0;

	return 0;
}

int StabModeler::objective(Weight<double> * w) {
	rmatind();
	rmatval();
	for (ccnt_v = 0; ccnt_v < n; ccnt_v++) {
		rmatind_v[ccnt_v] = ccnt_v + firstcol_v;
		rmatval_v[ccnt_v] = w->weight(ccnt_v);
	}

	return 0;
}

int StabModeler::startingpoint(int * S) {
	rmatind();
	rmatval();

	ccnt_v = 0;
	int i;
	for (i = 0; i < n; i++)
		if (S[i] >= 0) {
			rmatind_v[ccnt_v] = i + firstcol_v;
			rmatval_v[ccnt_v++] = S[i];
		}

	return 0;
}

// RepModeler

void RepModeler::init(Graph * g, int col, const char * prefix) {
	firstcol_v = col;
	nreps_v = n;
	firstrepcol = new int[n];
	mrep = new StabModeler *[n];
	grep = new Graph *[n];

	int sz = n*n - m;
	Rarray = new int[sz];
	R = new int*[n];
	rp_v = new int[n];
	rd_v = new int[n];

	// anti-neighborhoods
	int surplus;
	Graph * gc = g->complement();
	int err;
	err = gc->adjToArrays(sz, rd_v, Rarray, &surplus);
	assert(!err);
	delete gc;

	int i, j = 0;
	for (i = 0; i < n; i++) {
		if (Rarray[j] == i)
			rp_v[i] = 1;
		else
			rp_v[i] = 0;
		R[i] = &Rarray[j+rp_v[i]];
		j+=rd_v[i];
		rd_v[i] -= rp_v[i];
	}

	cliquerank();
	int csz = Graphs::dsaturSort(g, rd_v, R, n, cliquerank_v);
	printf("Clique cover size: %d\n", csz);

	int nrd;
	const int *rdarray;
	for (i = 0; i < n; i++) {
		R[i] -= rp_v[i];
		rdarray = rd(i, &nrd);
		grep[i] = g->homomorphism(nrd, rdarray);
		mrep[i] = NULL;
	}
	sprintf(this->prefix, "%s", prefix);
}

RepModeler::RepModeler(Graph * g, bool dummy) : StabModel(g) {
}

RepModeler::RepModeler(Graph * g) : StabModel(g) {
	init(g, 0, "x");
}

RepModeler::RepModeler(Graph * g, int col, const char * prefix) : StabModel(g) {
	init(g, col, prefix);
}

RepModeler::RepModeler(Graph * g, int * cr) : StabModel(g) {
	printf("RepModeler: Ignoring input cliquerank.\n");
	init(g, 0, "x");
}

RepModeler::RepModeler(Graph * g, int col, const char * prefix, int * cr) : StabModel(g) {
	printf("RepModeler: Ignoring input cliquerank.\n");
	init(g, col, prefix);
}

RepModeler::~RepModeler() {
	int i;
	for (i = 0; i < nreps_v; i++) {
		if (mrep[i] != NULL)
			delete mrep[i];
		if (grep[i] != NULL)
			delete grep[i];
	}
	delete firstrepcol;
	delete grep;
	delete mrep;
	delete Rarray;
	delete R;
	delete rp_v;
	delete rd_v;
}

int RepModeler::nreps() {
	return nreps_v;
}

const int * RepModeler::rp(int i, int *nrp) {
	*nrp = rp_v[i];
	return R[i];
}

const int * RepModeler::rd(int i, int * nrd) {
	*nrd = rd_v[i];
	return &R[i][rp_v[i]];
}

StabModeler * RepModeler::submodeler(int i, int col) {
	if (mrep[i] == NULL) {
		firstrepcol[i] = col;
		char namebuf[30];
		sprintf(namebuf, "%s^%d", prefix, g->vertex(i)+1);
		int * cr = new int[rd_v[i]];
		int j;
		for (j = 0; j < rd_v[i]; j++)
			cr[j] = cliquerank_v[R[i][rp_v[i]+j]];
		mrep[i] = ModelerFactory<StabModeler,Graph>::create(grep[i], col, namebuf, cr);
	}

	if (firstrepcol[i] != col)
		return NULL;
	return mrep[i];
}

int RepModeler::repcol(int rep) {
	int iv = 0;
	char namebuf[30];
	int ibuf = 0, lbuf;

	int storespc;
	cnamestore(&storespc);
	colname();
	type();
	rmatind();
	rmatval();
	rhs();
	sprintf(namebuf, "%s^%d", prefix, g->vertex(rep)+1);
	lbuf = strlen(namebuf)+1;
	colname_v[iv] = &cnamestore_v[ibuf];
	memcpy(colname_v[iv], namebuf, lbuf);
	rmatind_v[iv] = firstrepcol[rep] + rd_v[rep];
	rmatval_v[iv] = 0.0;
	rhs_v[iv] = 1.0;
	ccnt_v = 1;

	return 0;
}

int RepModeler::disjointrows() {
	// cover rows
	int i, spc;
	rnamestore(&spc);
	rowname();
	rmatbeg();
	rhs();
	rmatind();
	rmatval();

	// number of cover coefficients
	int j;
	int X[n];
	memset(X, 0, n*sizeof(int));
	nzcnt_v = 0;
	for (i = 0; i < nreps_v; i++) {
		for (j = 0; j < rp_v[i]; j++) {
			X[R[i][j]]++;
			nzcnt_v++;
		}
		for (j = 0; j < rd_v[i]; j++) {
			X[R[i][rp_v[i]+j]]++;
			nzcnt_v++;
		}
	}
	int ibuf = 0;
	i = 0;
	rhs_v[i] = 1.0;
	rmatbeg_v[i] = 0;
	rowname_v[i] = &rnamestore_v[ibuf];
	sprintf(rowname_v[i], "DISJ(%d)", g->vertex(i)+1);
	ibuf += strlen(rowname_v[i])+1;
	for (i = 1; i < n; i++) {
		rhs_v[i] = 1.0;
		rowname_v[i] = &rnamestore_v[ibuf];
		sprintf(rowname_v[i], "DISJ(%d)", g->vertex(i)+1);
		ibuf += strlen(rowname_v[i])+1;
		rmatbeg_v[i] = rmatbeg_v[i-1] + X[i-1];
	}
	rcnt_v = i;

	// cover coefficients
	for (i = 0; i < nreps_v; i++) {
		for (j = 0; j < rp_v[i]; j++) {
			int ind = rmatbeg_v[R[i][j]] + --X[R[i][j]];
			rmatind_v[ind] = firstrepcol[i] + rd_v[i];
			rmatval_v[ind] = 1.0;
		}
		for (j = 0; j < rd_v[i]; j++) {
			int ind = rmatbeg_v[R[i][rp_v[i]+j]] + --X[R[i][rp_v[i]+j]];
			rmatind_v[ind] = firstrepcol[i] + j;
			rmatval_v[ind] = 1.0;
		}
	}
	ccnt_v = 0;

	return 0;
}

int RepModeler::repedgesymcuts(int i) {
	// cover rows
	int spc;
	rnamestore(&spc);
	rowname();
	rmatbeg();
	rhs();
	rmatind();
	rmatval();

	// number of cover coefficients
	int j, k;
	int ibuf = 0;
	nzcnt_v = 0;
	rcnt_v = 0;
	for (j = nreps_v - 1; j > i; j--) {
		rhs_v[rcnt_v] = rp_v[j]-rp_v[i]-1.0;
		rowname_v[rcnt_v] = &rnamestore_v[ibuf];
		sprintf(rowname_v[rcnt_v], "EXC(%d->%d)", g->vertex(j)+1, g->vertex(i)+1);
		ibuf += strlen(rowname_v[rcnt_v])+1;
		rmatbeg_v[rcnt_v] = nzcnt_v;

		for (k = 0; k < rd_v[i]; k++)
			if (g->hasEdge(j, R[i][rp_v[i]+k])) {
				rmatind_v[nzcnt_v] = firstrepcol[i] + k;
				rmatval_v[nzcnt_v++] = -1.0;
			}
		if (nzcnt_v > rmatbeg_v[rcnt_v])
			rcnt_v++;
	}
	ccnt_v = 0;

	return 0;
}

int RepModeler::nrepsrow(int k) {
	int spc;
	rnamestore(&spc);
	rowname();
	rmatbeg();
	rhs();
	rmatind();
	rmatval();

	rhs_v[0] = k;
	rowname_v[0] = rnamestore_v;
	sprintf(rowname_v[0], "NREPS");
	rmatbeg_v[0] = 0;

	for (ccnt_v = 0; ccnt_v < n; ccnt_v++) {
		rmatind_v[ccnt_v] = firstrepcol[ccnt_v] + rd_v[ccnt_v];
		rmatval_v[ccnt_v] = 1.0;
	}
	rcnt_v = 1;
	nzcnt_v = ccnt_v;

	return 0;
}

int RepModeler::objective(Weight<double> * w) {
	rmatind();
	rmatval();
	for (ccnt_v = 0; ccnt_v < n; ccnt_v++) {
		rmatind_v[ccnt_v] = firstrepcol[ccnt_v] + rd_v[ccnt_v];
		rmatval_v[ccnt_v] = w->weight(ccnt_v);
	}

	return 0;
}

int RepModeler::repvar(int rep, char lu, double bd) {
	int spc;
	rnamestore(&spc);
	rowname();
	rmatind();
	rmatval();
	rowname_v[0] = rnamestore_v;
	rowname_v[0][0] = lu;
	rmatind_v[0] = firstrepcol[rep] + rd_v[rep];
	rmatval_v[0] = bd;

	return 0;
}

// RepModeler

ARepModeler::ARepModeler(Graph * g) : RepModeler(g, false) {
	ordered = new bool[n];
	memset(ordered, 0, n*sizeof(bool));
	init(g, 0, "x");
}

ARepModeler::ARepModeler(Graph * g, int col, const char * prefix) : RepModeler(g, false) {
	ordered = new bool[n];
	memset(ordered, 0, n*sizeof(bool));
	init(g, col, prefix);
}

ARepModeler::ARepModeler(Graph * g, int * cr) : RepModeler(g, false) {
	printf("RepModeler: Ignoring input cliquerank.\n");
	ordered = new bool[n];
	memset(ordered, 0, n*sizeof(bool));
	init(g, 0, "x");
}

ARepModeler::ARepModeler(Graph * g, int col, const char * prefix, int * cr) : RepModeler(g, false) {
	printf("RepModeler: Ignoring input cliquerank.\n");
	ordered = new bool[n];
	memset(ordered, 0, n*sizeof(bool));
	init(g, col, prefix);
}

ARepModeler::~ARepModeler() {
	delete ordered;
}

const int * ARepModeler::rd(int i, int * nrd) {
	if (!ordered[i]) {
		int j, l, aux;
		for (j = 0; j < rd_v[i]; j++) {
			for (l = 0; l < rp_v[i] && R[i][l] > R[i][rp_v[i]+j]; l++);
			if (l < rp_v[i]) {
				aux = R[i][rp_v[i]+j];
				R[i][rp_v[i]+j] = R[i][rp_v[i]+(--rd_v[i])];
				R[i][rp_v[i]+rd_v[i]] = aux;
				j--;
			}
		}
		ordered[i] = true;
	}

	return RepModeler::rd(i, nrd);
}
